import {ConditionBuilder} from '../conditions';
import {
  Entity,
  SQL_OPERATION_TYPE,
  SqlBuilderExtensions,
  SqlBuildResult,
  SqlOperationType,
  TableEntityMapping,
  UpdateFields
} from "./types";
import {SqlExecuteResult, SqlExecutor} from "../execution";

/**
 * 更新构建器
 * 用于构建UPDATE SQL语句
 */
export class UpdateBuilder<T> extends ConditionBuilder<T> {
  /** 表名 */
  private tableName: string;

  /** 实体映射信息 */
  private entityMapping?: TableEntityMapping;

  /** SQL操作类型 */
  private operationType: SqlOperationType = SQL_OPERATION_TYPE.UPDATE;

  /** 要更新的字段 */
  private updateFields: UpdateFields<T>;

  /** 是否返回受影响的行数 */
  private useReturning: boolean = false;

  /**
   * 是否使用兼容模式
   * SQLite 3.35.0 (2021-03-12)之前的版本不支持RETURNING子句
   */
  private useLegacyMode: boolean = false;

  /**
   * 构造函数
   * @param tableName 表名
   * @param updateFields 要更新的字段
   * @param entityMapping 实体映射信息（可选）
   * @param extensions SQL构建器扩展（可选）
   */
  constructor(
    tableName: string,
    updateFields: UpdateFields<T>,
    entityMapping?: TableEntityMapping,
    extensions?: SqlBuilderExtensions
  ) {
    super(undefined, extensions);
    this.tableName = tableName;
    this.updateFields = updateFields;
    this.entityMapping = entityMapping;
  }

  /**
   * 克隆当前构建器
   */
  protected clone(): UpdateBuilder<T> {
    const clone = new UpdateBuilder<T>(
      this.tableName,
      this.updateFields,
      this.entityMapping,
      this.extensions
    );

    clone.conditions = [...this.conditions];
    clone.parameters = {...this.parameters};
    clone.paramCounter = this.paramCounter;
    clone.useReturning = this.useReturning;
    clone.useLegacyMode = this.useLegacyMode;

    return clone;
  }

  /**
   * 处理字段名，增加对实体映射的支持
   * @param field 字段名
   */
  protected processFieldName(field: string): string {
    let processedField = field;

    // 如果有实体映射，转换属性名到字段名
    if (this.entityMapping && this.entityMapping.fields[field]) {
      processedField = this.entityMapping.fields[field].columnName;
    }

    // 调用父类处理方法
    return super.processFieldName(processedField);
  }

  /**
   * 设置要更新的字段
   * @param fields 要更新的字段
   */
  public set(fields: UpdateFields<T>): this {
    this.updateFields = {...this.updateFields, ...fields};
    return this;
  }

  /**
   * 设置兼容模式
   * 用于兼容SQLite 3.35.0以前的版本（不支持RETURNING子句）
   * @param useLegacyMode 是否使用兼容模式
   * @returns 当前构建器实例
   */
  public setLegacyMode(useLegacyMode: boolean): this {
    this.useLegacyMode = useLegacyMode;
    return this;
  }

  /**
   * 设置返回受影响的行数
   * 注意：需要SQLite 3.35.0或更高版本支持RETURNING子句
   * 对于低版本SQLite，请使用setLegacyMode(true)并通过changes属性获取受影响行数
   * @returns 当前构建器实例
   */
  public returning(): this {
    this.useReturning = true;
    return this;
  }

  /**
   * 构建SQL
   */
  public build(): SqlBuildResult {
    // 应用构建前钩子
    if (this.extensions?.sqlHooks?.beforeBuild) {
      this.extensions.sqlHooks.beforeBuild({
        operationType: this.operationType,
        tableName: this.tableName,
        updateFields: this.updateFields,
        conditions: this.conditions,
        returnChanges: this.useReturning
      });
    }

    if (Object.keys(this.updateFields).length === 0) {
      throw new Error('No fields provided for update operation');
    }

    // 构建UPDATE部分
    let sql = `UPDATE ${this.tableName}`;

    // 构建SET部分
    const setClauses: string[] = [];

    for (const key in this.updateFields) {
      if (Object.prototype.hasOwnProperty.call(this.updateFields, key)) {
        const field = this.processFieldName(key);
        const paramName = this.generateParamName(`${field}_update`);
        setClauses.push(`${field} = @${paramName}`);

        // 添加参数
        this.parameters[paramName] = this.processValue(this.updateFields[key as keyof T]);
      }
    }

    sql += ` SET ${setClauses.join(', ')}`;

    // 构建WHERE部分
    const whereClause = this.buildConditionsSql();
    if (whereClause) {
      sql += ` ${whereClause}`;
    }

    // 添加RETURNING子句
    if (this.useReturning && !this.useLegacyMode) {
      sql += ' RETURNING changes()';
    }

    // 创建结果
    const result: SqlBuildResult = {
      sql,
      params: this.parameters
    };

    // 应用构建后钩子
    if (this.extensions?.sqlHooks?.afterBuild) {
      return this.extensions.sqlHooks.afterBuild(result, {
        operationType: this.operationType,
        tableName: this.tableName
      });
    }

    return result;
  }

  /**
   * 将实体对象转换为可更新的数据
   * @param tableName 表名
   * @param entity 实体对象
   * @param entityMapping 实体映射信息（可选）
   * @param extensions SQL构建器扩展（可选）
   */
  public static fromEntity<E extends Entity>(
    tableName: string,
    entity: E,
    entityMapping?: TableEntityMapping,
    extensions?: SqlBuilderExtensions
  ): UpdateBuilder<E> {
    return new UpdateBuilder<E>(tableName, entity, entityMapping, extensions);
  }

  /**
   * 执行更新操作
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   * @returns 执行结果
   */
  public execute(executor?: SqlExecutor): SqlExecuteResult {
    const result = this.build();
    const actualExecutor = executor || this.getExecutor();

    if (!actualExecutor) {
      throw new Error('No SQL executor available. Please set an executor using setExecutor() or provide one as parameter.');
    }

    return actualExecutor.execute(result.sql, result.params);
  }

  /**
   * 执行更新操作并返回受影响的行数
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   * @returns 受影响的行数
   */
  public executeAffected(executor?: SqlExecutor): number {
    const result = this.execute(executor);
    return result.changes;
  }
}
